home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / cps / generic.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  51.7 KB  |  1,529 lines

  1. (* Copyright 1989 by AT&T Bell Laboratories *)
  2. functor CPSgen(M: CMACHINE) :
  3.   sig structure CPS : CPS
  4.     val codegen : CPS.function list * 
  5.               (CPS.lvar -> {known: Limit.kind, words_alloc: int}) *
  6.               ErrorMsg.complainer 
  7.              -> unit
  8.   end =
  9. struct
  10. open Array List
  11. infix 9 sub
  12.  
  13. fun dispose x = ()
  14.  
  15. val die = ErrorMsg.impossible
  16.  
  17. structure CPS = CPS
  18. open M System.Tags Access CPS
  19. val op sub = Array.sub
  20. structure CG = System.Control.CG
  21.  
  22. val globalvar : EA option = NONE  (* obsolete *)
  23.  
  24.  
  25. datatype RegType = FPReg | GPReg
  26.  
  27. (* FPR(fp,gp) => the variable is in the floating register fp _only_,
  28.  *         with an allocated general register gp
  29.  * DPR(fp,gp) => the variable is in _both_ a floating register fp,
  30.  *         and the general register gp.
  31.  * GPR gp     => the variable is n a general register gp only.
  32.  *)          
  33. datatype Reg = GPR of int        (* general purpose reg *)
  34.          | FPR of (int * int)     (* floating reg * shadow gp reg *)
  35.              | DPR of (int * int)    (* dual regs (fpr,gpr) *)
  36.  
  37. datatype generated = UNGEN of lvar list * cexp | GEN of lvar list * Reg list
  38.  
  39. datatype frag
  40.   = STANDARD of (lvar * lvar list * cexp) option ref * int
  41.   | KNOWN of generated ref
  42.   | KNOWN_CHECK of generated ref * int
  43.   | STRINGfrag of string
  44.   | REALfrag of string
  45. fun regtype2string rty = case rty of FPReg => "FPReg " | GPReg => "GPReg "
  46. fun reg2string reg = case reg 
  47.     of FPR(fp,gp) => "FPR(" ^ makestring fp ^ "," ^ makestring gp ^ ")"
  48.      | DPR(fp,gp) => "DPR(" ^ makestring fp ^ "," ^ makestring gp ^ ")"
  49.      | GPR gp => "GPR(" ^ makestring gp ^ ")"
  50. exception GpregNum and FpregNum and ShadowNum
  51. fun gpregNum reg = case reg 
  52.              of GPR gp => gp
  53.               | DPR(_,gp) => gp
  54.               | FPR _ => raise GpregNum
  55. fun fpregNum reg = case reg 
  56.              of FPR(fp,_) => fp
  57.               | DPR(fp,_) => fp
  58.               | GPR _ => raise FpregNum
  59. fun shadowNum reg = case reg
  60.               of FPR(fp,gp) => gp
  61.                | DPR(fp,gp) => gp
  62.                | GPR _ => raise ShadowNum
  63.  
  64. val allregs = standardlink::standardclosure::standardarg::standardcont::miscregs
  65.  
  66. val allfpregs = M.savedfpregs @ M.floatregs
  67. local 
  68.     exception FPRegEA and GPRegEA
  69.     val gpregarr = arrayoflist allregs
  70.     val fpregarr = arrayoflist allfpregs
  71. in 
  72. fun fpregEA reg = (fpregarr sub (fpregNum reg)) handle _ => raise FPRegEA
  73. fun gpregEA reg = (gpregarr sub (gpregNum reg)) handle _ => raise GPRegEA
  74. end
  75. val max_fp_parameters = let val len = length M.savedfpregs
  76.             in case M.floatregs 
  77.                  of [] => if len=0 then 0 else len-1
  78.                   | _ => len
  79.             end
  80. fun collect(_,[]) = []
  81.   | collect(pred,x::xs) = 
  82.     if pred x then x :: collect(pred,xs) else collect(pred,xs)
  83.  
  84. structure GetScratch :
  85.     sig
  86.     exception GetFpScratch
  87.     exception GetGpScratch
  88.     val getfpscratch: int * Reg list -> int
  89.     val getgpscratch: int * Reg list -> int
  90.     val arithtemp : EA
  91.     val fpregtemp : EA
  92.     val resetGetscratch : unit->unit
  93.     end =
  94. struct
  95. val ok_gpreg = array(length allregs, true)
  96. val ok_fpreg = array(length allfpregs, true)
  97. val last_gp = ref 0
  98. val last_fp = ref 0
  99. fun resetGetscratch () = (last_gp := 0; last_fp := 0)
  100. val len_gp = Array.length ok_gpreg
  101. val len_fp = Array.length ok_fpreg
  102. fun mark b reg = 
  103.     (*
  104.      * ~1 may be passed as a don't care register number,
  105.      * hence the handle Subscript ..
  106.      *)
  107.     let fun mboth(fp,gp) =
  108.     (update(ok_fpreg,fp,b) handle Subscript => ();
  109.      update(ok_gpreg,gp,b) handle Subscript => ())
  110.     in case reg
  111.      of GPR i => (update(ok_gpreg,i,b) handle Subscript => ())
  112.       | FPR(fp,gp) => mboth(fp,gp)
  113.       | DPR(fp,gp) => mboth(fp,gp)
  114.     end
  115. fun mark_prohibited proh = map (mark false) proh
  116.  
  117. fun cleanup regs = map (mark true) regs
  118. exception FindReg
  119. fun find_reg(okregs, next) =
  120.     let fun find i = if okregs sub i then i else find (i+1)
  121.     fun find2 i = if okregs sub i then i
  122.               else if i=next then raise FindReg else find2(i+1)
  123.     in  find next handle Subscript => find2 0
  124.     end
  125.  
  126. exception GetScratch
  127. fun getregscratch(pref, proh, okregs, last, len) = 
  128.     (mark_prohibited proh;
  129.      (if ((okregs sub pref) handle Subscript => false) then pref
  130.       else (find_reg(okregs, !last) 
  131.             handle FindReg => (cleanup proh; raise GetScratch)))
  132.       before
  133.       (cleanup proh;
  134.        last := (if !last+1=len then 0 else !last+1)))
  135.  
  136. exception GetFpScratch
  137. fun getfpscratch(pref,proh) = 
  138.     (getregscratch(pref, proh, ok_fpreg, last_fp, len_fp)
  139.          handle GetScratch => raise GetFpScratch)
  140.  
  141. exception GetGpScratch
  142. fun getgpscratch(pref,proh) = 
  143.     (getregscratch(pref, proh, ok_gpreg, last_gp, len_gp) 
  144.            handle GetScratch => raise GetGpScratch)
  145.  
  146. val arithtemp = case arithtemps 
  147.           of z::_ => z 
  148.            | _ => let val r = GPR(length(miscregs)+3)
  149.                            in mark false r; gpregEA r
  150.                           end
  151. val fpregtemp = 
  152.     (* see also max_fp_parameters *)
  153.     case allfpregs 
  154.       of [] => ErrorMsg.impossible "cps/generic: no floating point registers"
  155.        | _ => let val tmp_reg = length allfpregs - 1
  156.            in  mark false (FPR (tmp_reg,~1)); 
  157.            fpregEA (FPR(tmp_reg, ~1))
  158.            end
  159. end
  160. open GetScratch
  161.  
  162. fun codegen(funs : (lvar * lvar list * cexp) list, limits, err) =
  163. let 
  164.  
  165.     fun fromto(i,j) = if i > j then nil else ((GPR i)::fromto(i+1,j))
  166.     val k = !CG.calleesaves
  167.     val calleesaveregs = fromto(4,k+3)
  168.     fun standardformals args = 
  169.        let val t = length(args)
  170.         in if t = (k+4) then ([GPR 0,GPR 1,GPR 2,GPR 3]@calleesaveregs)
  171.            else if t = (k+2) then (GPR 3 :: GPR 2 :: calleesaveregs)
  172.                 else if ((t = 3) andalso (k = 0)) then [GPR 0,GPR 3,GPR 2]
  173.                      else ErrorMsg.impossible "110 in CPSgen"
  174.        end
  175.  
  176.     val _ = resetGetscratch()
  177.  
  178.     exception Labbind
  179.     val labtable : EA Intmap.intmap = Intmap.new(32, Labbind)
  180.     val addlabbinding = Intmap.add labtable
  181.     val labmap = Intmap.map labtable
  182.  
  183.     exception Know
  184.     val knowtable : frag Intmap.intmap = Intmap.new(32, Know)
  185.     val addknow = Intmap.add knowtable
  186.     val know = Intmap.map knowtable
  187.  
  188.     exception Freemap
  189.     val freemaptable : lvar list Intmap.intmap = Intmap.new(32, Freemap)
  190.     val freemap = Intmap.map freemaptable
  191.     val cexp_freevars = FreeMap.cexp_freevars freemap
  192.  
  193.     exception Regbind
  194.     val regbindtable : Reg Intmap.intmap = Intmap.new(32, Regbind)
  195.     val addregbinding = Intmap.add regbindtable
  196.     val regmap = Intmap.map regbindtable
  197.  
  198.     fun fpregbind_exists var = case regmap var of GPR _ => false | _ => true
  199.     fun gpregbind_exists var = case regmap var of FPR _ => false | _ => true
  200.     
  201.     exception GpregMap and FpregMap
  202.     fun gpregmap var = 
  203.     if gpregbind_exists var then regmap var else raise GpregMap
  204.     fun fpregmap var = 
  205.     if fpregbind_exists var then regmap var else raise FpregMap
  206.     
  207.     fun clean (VAR x::r) = x :: clean r
  208.       | clean (_::r) = clean r
  209.       | clean [] = []
  210.     fun live_regs(args:lvar list) = map regmap args
  211.     fun makefrag (f,vl,e) =
  212.         let val lab = newlabel()
  213.         val knowledge = 
  214.             case limits f
  215.              of {known=Limit.ESCAPES, words_alloc = alloc} => 
  216.                 STANDARD(ref(SOME(f,vl,e)), alloc)
  217.               | {known=Limit.KNOWN, ...} => 
  218.                 KNOWN(ref(UNGEN(vl,e)))
  219.               | {known=Limit.KNOWN_CHECK, words_alloc = alloc} => 
  220.                 KNOWN_CHECK(ref(UNGEN(vl,e)), alloc)
  221.         in  addknow(f, knowledge); 
  222.         addlabbinding(f,lab);
  223.         (lab,knowledge)
  224.         end
  225.     val frags = ref(map makefrag funs)
  226.     val _ = (dispose(limits,"limits"); dispose(makefrag,"makefrag");
  227.          dispose(funs,"funs"))
  228.     fun addfrag f = frags := f :: !frags
  229.  
  230.     exception Strings
  231.     local open IntStrMap
  232.           val m : EA intstrmap = new(32,Strings)
  233.     in fun enterString (s,lab) = add m (StrgHash.hashString(s),s,lab);
  234.        fun lookString s = map m (StrgHash.hashString(s),s)
  235.     end
  236.  
  237.     fun regbind(VAR v,regtype) = 
  238.     (*
  239.      * Returns a register binding for a cps value
  240.      * A write back is generated when a integer register binding is
  241.      * required for a value in a floating register.
  242.      *)
  243.     let val reg = regmap v
  244.     in case (reg,regtype)
  245.          of (FPR(fp,gp),GPReg) => 
  246.          let val newreg = DPR(fp,gp)
  247.          in storefloat(fpregEA newreg, gpregEA newreg);
  248.              addregbinding(v, newreg);
  249.              gpregEA newreg
  250.          end
  251.           | (_,GPReg) => gpregEA reg
  252.           | (_,FPReg) => fpregEA reg
  253.     end
  254.       | regbind(LABEL v, GPReg) = labmap v
  255.       | regbind(INT i, GPReg) = (immed(i+i+1) handle Overflow =>
  256.                ErrorMsg.impossible "Overflow in cps/generic.sml")
  257.       | regbind(STRING s, GPReg) =
  258.            (lookString s handle Strings =>
  259.               let val lab = newlabel()
  260.               in addfrag(lab, STRINGfrag s);
  261.                   enterString(s,lab);
  262.                   lab
  263.               end)
  264.       | regbind(REAL s, GPReg) = let val lab = newlabel()
  265.                  in  addfrag(lab, REALfrag s);
  266.                      lab
  267.                  end
  268.       | regbind(OBJECT _, GPReg) = ErrorMsg.impossible "OBJECT in cps/generic/regbind"
  269.       | regbind(_, FPReg) =
  270.     ErrorMsg.impossible "value not loaded into floating register"
  271.  
  272.     val gpregbind : value -> EA = fn x => regbind(x,GPReg)
  273.     val fpregbind : value -> EA = fn x => regbind(x,FPReg)
  274.  
  275.     exception RegMask
  276.     fun regmask formals =
  277.     let fun f (i,mask) =
  278.         case i
  279.           of GPR gp => Bits.orb(Bits.lshift(1,gp),mask)
  280.            | FPR _ => mask
  281.            | DPR _ => raise RegMask
  282.     in immed(fold f formals 0)
  283.     end
  284.  
  285.  
  286. (* add advanced register-targeting, currently the targeting depth is 4 if
  287.  * calleesaves > 0.
  288.  *  root1 : (lvar * ((lvar * Reg) list)) ref
  289.  *  root : cexp -> lvar * ((lvar * Reg) list)
  290.  *)
  291.  
  292.     val ss : int ref = ref(!CG.targeting)  (* global var *)
  293.  
  294.     fun merge2((v1,r1)::t1,(v2,r2)::t2) = 
  295.            if v1 = v2 then ((v1,r1)::merge2(t1,t2))
  296.            else if v1 < v2 then ((v1,r1)::merge2(t1,(v2,r2)::t2))
  297.                 else ((v2,r2)::merge2((v1,r1)::t1,t2))
  298.       | merge2(nil,t2) = t2
  299.       | merge2(t1,nil) = t1
  300.  
  301.     fun union2((f,t1),(_,t2)) = (f,merge2(t1,t2))
  302.  
  303.     fun mix(t1,t2) = 
  304.       let fun mix0((VAR v)::tl,r::rl) = (v,r)::mix0(tl,rl)
  305.             | mix0(_::tl,r::rl) = mix0(tl,rl)
  306.             | mix0(nil,nil) = nil
  307.             | mix0 _ = ErrorMsg.impossible "error in cps/generic/mix0"
  308.           val op slt = fn ((i,_),(j,_)) => (i < (j:int))
  309.        in Sort.sort (op slt) (mix0(t1,t2))
  310.       end
  311.  
  312.     fun gprfilter(f,tinfo) = 
  313.       let fun g((v,GPR r)::tl) = (v,GPR r)::(g tl)
  314.             | g((v,_)::tl) = (g tl)
  315.             | g nil = nil
  316.        in (f,g tinfo)
  317.       end
  318.  
  319.     fun targeting(wl,vl,e) = 
  320.       if !ss = 0 then nil 
  321.       else (let val olds = !ss
  322.                 val _ = (ss := olds-1)
  323.                 val (_,tinfo) = root(e)
  324.                 val _ = (ss := olds)
  325.  
  326.                 fun findv(v,nil) = NONE
  327.                   | findv(v,(w,r)::tl) = if v = w then (SOME r) else findv(v,tl)
  328.  
  329.                 fun extract(nil,nil) = nil
  330.                   | extract((VAR w)::wl,v::vl) = 
  331.                       (case findv(v,tinfo) of 
  332.                           NONE => extract(wl,vl)
  333.                         | (SOME r) => merge2([(v,r)],
  334.                                        (merge2([(w,r)],extract(wl,vl)))))
  335.                   | extract(_::wl,v::vl) =
  336.                       (case findv(v,tinfo) of 
  337.                           NONE => extract(wl,vl)
  338.                         | (SOME r) => merge2([(v,r)],extract(wl,vl)))
  339.                   | extract _ = ErrorMsg.impossible "errors in cps/generic/extract"
  340.              in extract(wl,vl)
  341.             end)
  342.     and getroot(APP(VAR f,wl)) = (f,mix(wl,standardformals wl))
  343.       | getroot(APP(LABEL f,wl)) = 
  344.          (case know f 
  345.             of KNOWN(ref(GEN(vl,fmls))) => (f,mix(wl@(map VAR vl),fmls@fmls))
  346.          | KNOWN(ref(UNGEN(vl,e))) => 
  347.                    (let val tmp = targeting(wl,vl,e)
  348.                      in (f,tmp)
  349.                     end)
  350.          | KNOWN_CHECK(ref(GEN(vl,fmls)),_) => (f,mix(wl@(map VAR vl),fmls@fmls))
  351.          | KNOWN_CHECK(ref(UNGEN(vl,e)),_) => 
  352.                    (let val tmp = targeting(wl,vl,e)
  353.                      in (f,tmp)
  354.                     end)
  355.          | STANDARD _ => (f,mix(wl,standardformals wl))
  356.          | _ => die "a10 in CPSgen")
  357.  
  358.       | getroot _ = ErrorMsg.impossible "errors in cps/generic/getroot"
  359.     and root(RECORD(_,_,_,e)) = root e
  360.       | root(SELECT(_,_,_,e)) = root e
  361.       | root(OFFSET(_,_,_,e)) = root e
  362.       | root(SWITCH(_,_,el)) = fold union2 (map root el) (0,nil)
  363.       | root(SETTER(_,_,e)) = root e
  364.       | root(LOOKER(_,_,_,e)) = root e
  365.       | root(ARITH(_,_,_,e)) = root e
  366.       | root(PURE(_,_,_,e)) = root e
  367.       | root(BRANCH(_,_,_,e1,e2)) = union2 (root e1, root e2)
  368.       | root(e as APP _) = gprfilter (getroot e)
  369.       | root _ = die "a9 in CPSgen"
  370.     val root1 :(lvar * ((lvar * Reg) list)) ref = ref((0,nil))
  371.  
  372.     fun nextuse x =
  373.     let fun xin[] = false 
  374.           | xin(VAR y::r) = x=y orelse xin r 
  375.           | xin(_::r) = xin r
  376.         fun g(level,a) =
  377.         let val rec f =
  378.             fn ([],[]) => level
  379.              | ([],next) => g(level+1,next)
  380.              | (SWITCH(v,_,l)::r,next) => 
  381.                if xin[v] then level else f(r,l@next)
  382.              | (RECORD(_,l,w,c)::r,next) =>
  383.                if xin(map #1 l) then level 
  384.                else f(r,c::next)
  385.              | (SELECT(i,v,w,c)::r,next) => 
  386.                if xin[v] then level else f(r,c::next)
  387.              | (OFFSET(i,v,w,c)::r,next) => 
  388.                if xin[v] then level else f(r,c::next)
  389.              | (SETTER(i,a,c)::r,next) => 
  390.                if xin a then level else f(r,c::next)
  391.              | (LOOKER(i,a,w,c)::r,next) => 
  392.                if xin a then level else f(r,c::next)
  393.              | (ARITH(i,a,w,c)::r,next) => 
  394.                if xin a then level else f(r,c::next)
  395.              | (PURE(i,a,w,c)::r,next) => 
  396.                if xin a then level else f(r,c::next)
  397.              | (BRANCH(i,a,c,e1,e2)::r,next) => 
  398.                if xin a then level else f(r,e1::e2::next)
  399.              | (APP(v,vl)::r,next) => 
  400.                if xin(v::vl) then level 
  401.                else f(r,next)
  402.              | _ => die "a8 in CPSgen"
  403.         in f(a,[])
  404.         end
  405.         fun h y = g(0,[y])
  406.     in h
  407.     end
  408.  
  409.     fun next_fp_use(x,cexp) : int option = 
  410.     let val there = exists (fn VAR x' => x=x'| _ => false)
  411.         fun fp_use(SETTER(P.updatef,[_,_,VAR x'],_)) = x'=x
  412.           | fp_use(ARITH(P.fadd,vl,_,_)) = there vl
  413.  
  414.           | fp_use(ARITH(P.fdiv,vl,_,_)) = there vl
  415.           | fp_use(ARITH(P.fmul,vl,_,_)) = there vl
  416.           | fp_use(ARITH(P.fsub,vl,_,_)) = there vl
  417.           | fp_use(BRANCH(P.fge,vl,_,_,_)) = there vl
  418.           | fp_use(BRANCH(P.fgt,vl,_,_,_)) = there vl
  419.           | fp_use(BRANCH(P.fle,vl,_,_,_)) = there vl
  420.           | fp_use(BRANCH(P.flt,vl,_,_,_)) = there vl
  421.           | fp_use(BRANCH(P.feql,vl,_,_,_)) = there vl
  422.           | fp_use(BRANCH(P.fneq,vl,_,_,_)) = there vl
  423.           | fp_use _ = false
  424.         fun f (cexp,level) =
  425.             case cexp
  426.           of RECORD(_,_,_,ce) => f(ce,level+1)
  427.            | SELECT(_,_,_,ce) => f(ce,level+1)
  428.            | OFFSET(_,_,_,ce) => f(ce,level+1)
  429.            | APP _ => NONE
  430.            | FIX _ => ErrorMsg.impossible "FIX in generic.sml"
  431.            | SWITCH(_,_,cl) => fpop_in_all_branches(cl,level)
  432.            | SETTER(_,_,ce) => f(ce,level+1)
  433.            | LOOKER(_,_,_,ce) => f(ce,level+1)
  434.            | PURE(_,_,_,ce) => f(ce,level+1)
  435.            | ARITH(_,_,_,ce) => if fp_use cexp then SOME level
  436.                      else f(ce,level+1)
  437.            | BRANCH(_,_,_,c1,c2) => if fp_use cexp then SOME level
  438.                       else fpop_in_all_branches([c1,c2],level)
  439.         and
  440.         fpop_in_all_branches (branches,level) =
  441.         let val all_branches =  map (fn c => f(c,level)) branches
  442.         in if exists (fn opt => opt = NONE) all_branches  
  443.                then NONE
  444.            else let val lvls = map (fn SOME l => l
  445.                          | _ => die "a8 in CPSgen") 
  446.                                    all_branches
  447.             in SOME (fold min lvls (hd lvls))
  448.             end
  449.         end
  450.     in f(cexp,0)
  451.     end
  452.  
  453.     fun preferred_register_asgn(formals,cexp) =
  454.     if max_fp_parameters=0 then map (fn _ => GPReg) formals
  455.  
  456.     else 
  457.           let val preferred_regs =  
  458.               map (fn SOME x => (FPReg,x) | NONE => (GPReg, 0))
  459.               (map (fn v => next_fp_use(v,cexp)) formals)
  460.           fun assign([],_) = []
  461.         | assign(xs,0) = map (fn _ => GPReg) xs
  462.         | assign((GPReg,_)::xs,acc) = GPReg::assign(xs,acc)
  463.         | assign((FPReg,lvl)::xs,acc) =
  464.           let fun better_params([],c) = c
  465.             | better_params((FPReg,lvl')::xs, c) =
  466.               if lvl' < lvl then better_params(xs,c+1)
  467.               else better_params(xs,c)
  468.             | better_params(_::xs,c) = better_params(xs,c)
  469.           in if better_params(xs,0) >= acc then GPReg::assign(xs,acc)
  470.              else FPReg::assign(xs,acc-1)
  471.           end
  472.       in assign(preferred_regs, max_fp_parameters)
  473.       end
  474.  
  475.     val any = INT 0 (* default argument for alloc *)
  476.  
  477.     fun alloc(v,default,continue) =
  478.     (*
  479.      * allocate a general purpose register for the new
  480.      * free variable v, and continue.
  481.      *)
  482.     let val (f,tinfo) = !root1
  483.  
  484.         val proh = live_regs (freemap v)
  485.         fun delete (z,nil) = nil
  486.           | delete (z:Reg, a::r) = if a=z then delete(z,r) else (a::delete(z,r))
  487.         val default = case default
  488.                 of VAR i => ((gpregmap i) handle GpregMap => GPR ~1)
  489.                  | _ => GPR ~1
  490.         fun get(good,bad) =
  491.         let val r = getgpscratch(gpregNum good,bad@proh) 
  492.                     handle GetGpScratch => 
  493.                               getgpscratch(gpregNum default,proh)
  494.                  | GpregNum => 
  495.                           getgpscratch(gpregNum default, proh)
  496.         in addregbinding(v,GPR r); continue(gpregEA (GPR r))
  497.         end
  498.         fun find tinfo =
  499.         let fun g((w,r)::tl) =
  500.                 if w=v then get(r, delete(r,map #2 tinfo))
  501.             else g tl
  502.               | g _ = get(default, map #2 tinfo)
  503.         in g tinfo
  504.         end
  505.     in find tinfo
  506.     end
  507.  
  508.     fun partition_args(args:value list, formals:Reg list) =
  509.     (*
  510.      * Moves registers to the right register class.
  511.      * This makes it easier to shuffle later.
  512.      * If an actual argument is required in both a floating and
  513.      * general register then it will end up in a DPR register.
  514.      *
  515.      * The process is split into 3 phases.
  516.      * 1. move_GPR_args moves arguments into GPRegs that do not have
  517.      *   a GPReg binding.
  518.      * 2. flush_fpregs removes all unnecessary bindings in 
  519.      *   floating registers.
  520.      * 3. move_FPR_args moves arguments into FPRegs.
  521.      *)
  522.     let fun move_GPR_args(VAR var::vs, GPR gp::fmls) = 
  523.             if gpregbind_exists var then  move_GPR_args(vs,fmls)
  524.         else let val FPR(fp,gp) = regmap var
  525.              val newreg = DPR(fp,gp)
  526.              in (*
  527.              * Use shadow register to store floating value.
  528.              *)
  529.              storefloat(fpregEA newreg, gpregEA newreg);
  530.              addregbinding(var,newreg);
  531.              move_GPR_args(vs,fmls)
  532.              end
  533.           | move_GPR_args (_::a,_::f) = move_GPR_args(a,f)
  534.           | move_GPR_args ([],[]) = ()
  535.           | move_GPR_args _ =
  536.         ErrorMsg.impossible "cps/generic/partition_args/move_GPR_args"
  537.         fun flush_fpregs () =
  538.             let open SortedList
  539.             fun GPRonly_args() =
  540.               let val pairs = List2.map2 (fn x => x) (args,formals)
  541.               val inFPRegs = 
  542.                   collect(fn (VAR _,FPR _) => true | _ =>false,pairs)
  543.               val inGPRegs = 
  544.                   collect(fn (VAR _,GPR _)=> true | _ =>false,pairs)
  545.               val h = fn (VAR x,_) => x | _ => die "a7 in CPSgen"
  546.               in difference (uniq(map h inGPRegs),uniq(map h inFPRegs))
  547.               end
  548.             fun f (d::ds) = 
  549.             let val reg = regmap d 
  550.             in case reg 
  551.                  of DPR(fp,gp) => 
  552.                  (* release floating point register *)
  553.                  (addregbinding(d, GPR gp); f ds)
  554.                   | GPR _ => f ds
  555.                   | FPR _ => ErrorMsg.impossible
  556.                     "cps/generic/partition_args/flush_fpregs"
  557.             end
  558.               | f [] = ()
  559.         in f (GPRonly_args())
  560.         end
  561.         val formal_fp_regs = 
  562.         let fun f (r::regs) = 
  563.             (case r 
  564.                of FPR(fp,_) => fp::f regs 
  565.             | DPR(fp,_) => ErrorMsg.impossible
  566.                               "cps/generic/partition_args/formal_fp_regs"
  567.             | _ => f regs)
  568.               | f [] = []
  569.         in f formals
  570.         end
  571.         fun move_FPR_args(VAR v::vs, (FPR(fp,_)::fmls)) =
  572.         let fun getfpreg pref =
  573.                 (* 
  574.              * The preferred floating register is the corresponding
  575.              * formal floating register, so this is deleted from
  576.              * the formals in a first attempt at getting a floating
  577.              * register.
  578.              *)
  579.                 let fun delete (_,[]) = []
  580.                   | delete (r,r'::rest) = if r=r' then rest 
  581.                               else r'::delete(r,rest)
  582.                 val liveregs = live_regs (clean args)
  583.                 val avoid = map (fn r => FPR(r,~1)) 
  584.                             (delete(pref,formal_fp_regs))
  585.             in getfpscratch(pref, liveregs@avoid)
  586.                    handle GetFpScratch => 
  587.                          getfpscratch(pref,liveregs)
  588.             end
  589.         in if fpregbind_exists v then move_FPR_args(vs,fmls)
  590.            else let val z = getfpreg fp
  591.                 val r = gpregNum (regmap v)
  592.                 val newreg = DPR(z,r)
  593.             in loadfloat(gpregEA newreg, fpregEA newreg);
  594.                 addregbinding(v, newreg);
  595.                 move_FPR_args(vs,fmls)
  596.             end
  597.         end
  598.           | move_FPR_args(_::a,_::f) = move_FPR_args(a,f)
  599.           | move_FPR_args([],[]) = ()
  600.           | move_FPR_args _ = 
  601.         ErrorMsg.impossible "cps/generic/partition_args/move_FPR_args"
  602.     in  move_GPR_args(args, formals);
  603.         if exists (fn FPR _ => true | _ => false) formals then
  604.         (flush_fpregs (); move_FPR_args(args, formals))
  605.         else ()
  606.     end
  607.  
  608.     fun shuffle_regtype(args:value list,formals:Reg list,regtype:RegType) =
  609.     (*
  610.      *  Move actual arguments into registers for function call.
  611.      * Assumes that all the variable actuals have a binding in 
  612.      * the correct register class.
  613.      * If an actual is being passed in a floating and general 
  614.      * register, then its binding must be a DPR register.
  615.      * The function shuffles register of a specific type
  616.      * i.e. FPReg, GPReg.
  617.      *)
  618.     let val (tempreg,EAfcn,regnum) =
  619.         case regtype of GPReg => (arithtemp,gpregEA,gpregNum)
  620.                               | FPReg => (fpregtemp,fpregEA,fpregNum)
  621.         fun classify(VAR v::al, f::fl, match, nomatch, notinreg) =
  622.         let val v' = regmap v
  623.         in if regnum v' = regnum f
  624.                then classify(al,fl,regnum f::match,nomatch,notinreg)
  625.            else classify(al,fl,match,(v',f)::nomatch,notinreg)
  626.         end
  627.           | classify(a::al,f::fl, m,n,notinreg) = 
  628.          classify(al,fl,m,n,(a,f)::notinreg)
  629.           | classify(_,_, m,n,nr) = (m,n,nr)
  630.         fun f (pairs,used) = 
  631.           let val u' = (map (regnum o #1) pairs) @ used
  632.           fun movable (a, b) = not (exists (fn z => z = regnum b) u')
  633.           fun split pred nil = (nil,nil)
  634.             | split pred (a::r) =
  635.               let val (x,y) = split pred r
  636.               in if pred a then (a::x, y) else (x, a::y)
  637.               end
  638.           in case split movable pairs
  639.            of (nil,_) => (pairs,used)
  640.             | (m,m') => (app (fn(a,b)=>move(EAfcn a, EAfcn b)) m;
  641.                  f(m', (map (regnum o #2) m) @ used))
  642.           end
  643.             fun cycle(pairs, used) =
  644.         case f(pairs,used)
  645.           of (nil,_) => ()
  646.            | ((a,b)::r, used) =>
  647.              cycle(move(EAfcn a, tempreg);
  648.                    f(r,used) before move(tempreg, EAfcn b))
  649.         val (matched,notmatched,notinreg) = classify(args,formals,[],[],[])
  650.     in
  651.           cycle(notmatched,matched);
  652.       app (fn (a,b) => 
  653.               case regtype
  654.             of GPReg => move(gpregbind a, EAfcn b)
  655.              | FPReg => loadfloat(gpregbind a, EAfcn b))
  656.           notinreg
  657.     end
  658.  
  659.     fun do_shuffle(args:value list,formals:Reg list) =
  660.     (*
  661.      * - Partitions the actual arguments into sets
  662.      * based on their destination class.
  663.      * i.e. All agruments headed for general registers are
  664.      * in one partition, and all arguments headed for floating
  665.      * registers in another.
  666.      *)
  667.     let fun register_sets(v::vs,f::fs,gv,gf,fv,ff) =
  668.         (case f 
  669.             of GPR _ => register_sets(vs,fs,v::gv,f::gf,fv,ff)
  670.              | FPR _ => register_sets(vs,fs,gv,gf,v::fv,f::ff)
  671.              | DPR _ => ErrorMsg.impossible "cps/generic/do_shuffle")
  672.           | register_sets([],[],gv,gf,fv,ff) = ((gv,gf,GPReg),(fv,ff,FPReg))
  673.           | register_sets _ = ErrorMsg.impossible "register_sets/do_shuffle"
  674.     
  675.         val _ = partition_args(args,formals)
  676.         val (gp_set,fp_set) = register_sets(args,formals,[],[],[],[])
  677.     in shuffle_regtype gp_set;
  678.        shuffle_regtype fp_set
  679.     end
  680.  
  681.     fun allocparams(args:value list, formals:lvar list, prefer:RegType list) =
  682.        (* 
  683.     * Determines the parameter passing convention for a function.
  684.         * This is complicated by the fact that an actual may not be in the
  685.     * appropriate register class.
  686.     * Even if an actual is in the correct register class it may not
  687.     * be in a suitable register, since only a specific set of registers
  688.     * can be used for parameter passing.
  689.     * Precondition: 
  690.     *     |formals| <= maxfree && |live_regs(clean args)| <= maxfree
  691.     * Invariant pass1:
  692.     *     |live_regs(clean(args)| + used_gp <= maxfree
  693.     *) 
  694.     let open SortedList
  695.         datatype PRegs = 
  696.         OK of Reg     (* allocated general registers *)
  697.           | NO of int    (* allocated shadow register for a float *)
  698.         val liveregs = live_regs (clean args)
  699.         fun getgpr avoid =
  700.         getgpscratch(~1, liveregs @ (map GPR avoid)) 
  701.         handle GetGpScratch =>
  702.          (System.Print.say "allocparams\n";
  703.           raise GetGpScratch)
  704.         fun okFPR_param fpr = fpr < max_fp_parameters
  705.         fun inuse (reg,already) = exists (fn r => r=reg) already
  706.             val (_,tinfo) = !root1
  707.             fun findv v = 
  708.                let fun g((w,r)::tl) = (if w = v then (SOME (gpregNum r)) else g(tl))
  709.                      | g nil = NONE
  710.                 in g tinfo
  711.                end
  712.  
  713.         (* pass1 is guided by the preferred register class.
  714.          * If an actual is in the right register class and has not been 
  715.          * assigned then it is marked as being assigned.
  716.          * Otherwise an allocation is made.
  717.          * The shadow register is used where appropriate. 
  718.          *)
  719.         fun pass1 (VAR v::vl, p::pref, used_gp, used_fp,u::ul) =
  720.         (case p
  721.            of GPReg =>
  722.                let fun test_gp_reg z =
  723.                    if inuse(z,used_gp) 
  724.                                then (case (findv u) of 
  725.                                        NONE => (getgpr used_gp)
  726.                                      | (SOME r) => if inuse(r,used_gp) 
  727.                                                    then getgpr used_gp
  728.                                                    else r) 
  729.                    else z
  730.                fun pass1_with_gpreg z =
  731.                    let val w = test_gp_reg z
  732.                    in OK(GPR w)::pass1(vl,pref,w::used_gp,used_fp,ul)
  733.                    end
  734.                val reg = regmap v
  735.                in if gpregbind_exists v 
  736.               then pass1_with_gpreg(gpregNum reg)
  737.               else pass1_with_gpreg(shadowNum reg)
  738.                end
  739.             | FPReg =>
  740.               let fun bad_fpreg gp =
  741.                   let val r = if not(inuse(gp,used_gp)) then gp
  742.                       else getgpr used_gp
  743.                   in NO r:: pass1(vl,pref,r::used_gp,used_fp,ul)
  744.                   end
  745.               val reg = regmap v
  746.               in if fpregbind_exists v then
  747.                 let val z = fpregNum reg
  748.                 val r = shadowNum reg
  749.                 in if okFPR_param z andalso 
  750.                   not (inuse(z,used_fp)) andalso
  751.                   not (inuse(r,used_gp))
  752.                    then OK(FPR(z,r))::
  753.                     pass1(vl,pref,r::used_gp,z::used_fp,ul)
  754.                    else bad_fpreg r
  755.                 end
  756.              else bad_fpreg (gpregNum reg)
  757.               end)
  758.           | pass1 (_::vl, p::pref, used_gp, used_fp, u::ul) =
  759.         let val z = (case (findv u) of
  760.                                NONE => (getgpr used_gp) 
  761.                              | (SOME w) => (if inuse(w,used_gp) 
  762.                                             then getgpr used_gp
  763.                                             else w))
  764.         in (case p of GPReg => OK(GPR z) | FPReg => NO z) ::
  765.             pass1(vl,pref,z::used_gp,used_fp,ul)
  766.         end
  767.           | pass1 ([],[],_,_,[]) = []
  768.           | pass1 _ =
  769.         ErrorMsg.impossible "cps/generic/allocparams/pass1"
  770.         fun assigned_FPregs assgm =
  771.         map (fn OK(FPR(fp,_)) => fp
  772.               | _ => die "a6 in CPSgen")
  773.             (collect(fn OK(FPR(fp,_))=> true | _ => false,assgm))
  774.         fun pass2 asgm =
  775.         let val savedFPRegs = 
  776.                 let fun from (n,m) = 
  777.                     if n >= m then [] else n::from(n+1,m)
  778.             in from (0, max_fp_parameters)
  779.             end
  780.             val unusedfpr = difference (uniq savedFPRegs,
  781.                         uniq (assigned_FPregs asgm))
  782.             fun pass2(NO gp::pregs,fp::fpregs)=
  783.             FPR(fp,gp)::pass2(pregs,fpregs)
  784.               | pass2(NO _ ::pregs, []) =
  785.             ErrorMsg.impossible "cps/generic/allocparams/pass2"
  786.               | pass2(OK reg::pregs, fpregs) = reg :: pass2(pregs,fpregs)
  787.               | pass2 ([],_) = []
  788.         in pass2(asgm, unusedfpr)
  789.         end
  790.         val assign1 = pass1(args,prefer,[],[],formals)
  791.         val final = if exists (fn rty => rty = FPReg) prefer
  792.                 then pass2 assign1
  793.             else map (fn (OK r) => r
  794.                    | _ => die "a5 in CPSgen") assign1
  795.     in
  796.         
  797.         List2.app2 addregbinding (formals,final);
  798.         do_shuffle(args, final);
  799.         final
  800.     end
  801.  
  802.     fun stupidargs(f,args,vl,pref) = 
  803.     (*
  804.      * - assign integer and floating registers in sequence
  805.      * starting from 0.
  806.      *)
  807.     let fun argregs(v::rest,p::pref,gpreg,fpreg) =
  808.             (case p 
  809.            of GPReg => 
  810.                (addregbinding(v,GPR gpreg);
  811.             GPR gpreg::argregs(rest,pref,gpreg+1,fpreg))
  812.             | FPReg => 
  813.                let val newreg = FPR(fpreg,gpreg)
  814.                in addregbinding(v,newreg);
  815.                newreg::argregs(rest,pref,gpreg+1,fpreg+1)
  816.                end)
  817.           | argregs ([],_,_,_) = []
  818.           | argregs _ = ErrorMsg.impossible "cps/generic/stupidargs"
  819.         val formals = argregs(vl,pref,0,0)
  820.     in  do_shuffle(args,formals); formals
  821.     end
  822.  
  823.     fun force_fpgetscratch (pref:int, proh:Reg list, cexp) =
  824.     (*
  825.      * - allocate a floating point registers spilling if necessary.
  826.      * The floating registers in proh cannot be spilled.
  827.      * All free variables in cexp must have a register binding.
  828.      *)
  829.       let val free = cexp_freevars cexp
  830.       exception Spill
  831.       fun spill():lvar =
  832.           let fun find_fp_spill_reg [] = raise Spill
  833.             | find_fp_spill_reg ((_,v)::uv) = 
  834.               if fpregbind_exists v
  835.                       then let val r = fpregmap v
  836.                in if exists (fn reg => fpregNum reg = fpregNum r) 
  837.                             proh
  838.                   then find_fp_spill_reg uv
  839.                   else v
  840.                end
  841.               else find_fp_spill_reg uv
  842.           val sortdecreasing = 
  843.               Sort.sort (fn ((i:int,_),(j:int,_)) => i < j)
  844.           val uses = map (fn v =>(nextuse v cexp, v)) free
  845.           in find_fp_spill_reg (sortdecreasing uses)
  846.           end
  847.       fun duplicates(vl:lvar list) =
  848.           let val avoid = 
  849.               (map fpregNum proh) handle RegNum => ErrorMsg.impossible
  850.               "cps/generic/force_getfpscratch/duplicates"
  851.           fun bad_dup v = exists (fn r => v = r) avoid
  852.           fun f (x::xs) = 
  853.               let val r = regmap x
  854.               in case r 
  855.                of DPR (fp,gp) => 
  856.                    if bad_dup fp then f xs else (x,fp,gp)::f xs  
  857.                 | _ => f xs
  858.               end
  859.             | f [] = []
  860.           in f vl
  861.           end
  862.       fun pref_dup [] = NONE
  863.         | pref_dup ((a as (v,fp,gp))::ds) =
  864.           if fp = pref then SOME a else pref_dup ds
  865.  
  866.       exception FirstNoneUse of lvar
  867.       fun find_good_dup dups = 
  868.           let val sort = 
  869.           Sort.sort (fn ((_,lvl1),(_,lvl2)) => lvl1 <= lvl2)
  870.           val f = (fn (v,fp,gp) => case next_fp_use(v,cexp) 
  871.                          of NONE => raise FirstNoneUse v
  872.                           | SOME lvl => (v,lvl))
  873.           in #1 (hd (sort (map f dups)))
  874.           end
  875.  
  876.       fun nofpr_handle () =
  877.           let val dups = duplicates free
  878.           in 
  879.           case pref_dup dups
  880.             of SOME(v,fp,gp) => 
  881.             (addregbinding(v,GPR gp); fp)
  882.              | NONE => 
  883.             if null dups then
  884.                 let val z = (spill() handle Spill => 
  885.                                 raise GetFpScratch)
  886.                 val r as FPR(fp,gp) = fpregmap z
  887.                 val newreg = GPR gp
  888.                 in storefloat(fpregEA r, gpregEA newreg);
  889.                 addregbinding(z, newreg);
  890.                 fp
  891.                 end 
  892.             else
  893.                 (*
  894.                  * Find the dup that is not going to be used
  895.                  * in a floating context or one that is
  896.                  * going to be used the furthest away.
  897.                  *)
  898.                 let val v = (find_good_dup dups) 
  899.                         handle FirstNoneUse x => x
  900.                 val DPR(fp,gp) = regmap v
  901.                 in addregbinding(v, GPR gp); fp
  902.                 end
  903.           end
  904.       in  getfpscratch (pref, proh @ live_regs free)
  905.       handle GetFpScratch => (nofpr_handle ())
  906.       end
  907.  
  908.     exception MoveToFPRs
  909.     fun move_to_FPRs(vl, cexp) =
  910.     (*
  911.      * move variables in vl to floating registers.
  912.      *)
  913.     let fun f (VAR x::r,moved) =
  914.         if fpregbind_exists x then f(r, regmap x::moved)
  915.         else let val fp = force_fpgetscratch(~1,moved,cexp)
  916.              val gp = gpregNum(regmap x)
  917.              val newreg = DPR(fp,gp)
  918.              in loadfloat(gpregEA newreg,fpregEA newreg);
  919.              addregbinding(x, newreg);
  920.              f(r, newreg::moved)
  921.              end
  922.           | f (a::r,moved) =
  923.         (*
  924.          * There is never a register allocated for constants.
  925.          * So when moving constants into floating point registers
  926.          * we _must_ not allocate the shadow register.
  927.          *)
  928.         let val fp = force_fpgetscratch(~1,moved,cexp)
  929.             val newreg = FPR(fp, ~1)
  930.         in loadfloat(gpregbind a,fpregEA newreg);
  931.             f(r, newreg::moved)
  932.         end
  933.           | f ([],moved) = rev moved
  934.     in f(vl,[])
  935.     end
  936.  
  937.     fun do_fp_primop (args,w,e,cexp,continue) =
  938.     (* 
  939.      * ensure that the required arguments are in floating 
  940.      * registers and allocates a FPR for the result.
  941.      *)
  942.     let
  943.         val moved  = move_to_FPRs(args,cexp)
  944.         val u = getgpscratch(~1, live_regs(freemap w))
  945.         (* 
  946.          * A lie to guarantee precondition for force_fpgetscratch
  947.          * which we promptly confess when creating newreg
  948.          *)
  949.         val _ = addregbinding(w, GPR u) 
  950.         val z = let 
  951.             (* clean_fpregs:
  952.              * This function is required because of the M68k 
  953.              * that does not support 3 operand floating point 
  954.              * instructions. See definition of float in m68.sml
  955.              *
  956.              * Clean_fpregs removes the shadow registers in the
  957.              * moved set.
  958.              * Saying that they are prohibited is not strictly 
  959.              * correct. 
  960.              *)
  961.             fun clean_fpregs [] = []
  962.               | clean_fpregs (x::xs) = 
  963.                 (case x 
  964.                    of FPR(fp,_) => FPR(fp, ~1) :: clean_fpregs xs
  965.                 | DPR(fp,_) => DPR(fp, ~1) :: clean_fpregs xs
  966.                 | GPR _ => ErrorMsg.impossible 
  967.                             "cps/generic/do_fp_primop")
  968.             in force_fpgetscratch(~1, clean_fpregs moved, e)
  969.             end
  970.         val newreg = FPR(z,u)
  971.     in  addregbinding(w,newreg);
  972.         continue (map fpregEA moved, fpregEA newreg)
  973.     end
  974.  
  975.     fun tempreg(x,f) = case arithtemps of _::z::_ => f z | _ => f x
  976.  
  977.     fun genfrag (_, STANDARD(ref NONE,_)) = ()
  978.       | genfrag (lab, STANDARD(r as ref (SOME(fname,fmls,e)), alloc)) =
  979.     let val fmls' as linkreg::_ = standardformals fmls
  980.     in  r := NONE;
  981.           Intmap.clear regbindtable;
  982.         FreeMap.freemap (Intmap.add freemaptable) e;
  983.         List2.app2 addregbinding (fmls, fmls');
  984.         align(); mark();
  985.         comment(Access.lvarName fname ^ ":\n");
  986.             define lab;
  987.             beginStdFn(lab, gpregEA linkreg);
  988.             checkLimit (alloc*4, gpregEA linkreg, regmask fmls');
  989.             root1 := root e;
  990.             gen e;
  991.           Intmap.clear freemaptable
  992.     end
  993.       | genfrag (_, KNOWN _) = ()
  994.       | genfrag (_, KNOWN_CHECK _) = ()
  995.       | genfrag (lab, REALfrag r) = 
  996.     (align(); 
  997.      mark(); 
  998.      emitlong(desc_embedded_reald);
  999.      define lab; 
  1000.      comment("# real constant " ^ r ^ "\n");
  1001.      realconst r
  1002.      handle M.BadReal r =>
  1003.        err ErrorMsg.COMPLAIN ("real constant out of range: " ^ r)
  1004.          ErrorMsg.nullErrorBody)
  1005.       | genfrag (lab, STRINGfrag s) = 
  1006.     (align(); 
  1007.      mark();
  1008.      emitlong(make_desc(size s, tag_embedded_string));
  1009.      define lab; 
  1010.      emitstring s; 
  1011.      align())
  1012.  
  1013.     (* generate a new code label *)
  1014.     and genlab(lab, cexp) = (root1 := root cexp; define lab; gen cexp)
  1015.  
  1016.     and parallel_gen (shared_vars, f1, f2) =
  1017.     let val bindings = map regmap shared_vars
  1018.     in f1(); 
  1019.        List2.app2 addregbinding (shared_vars,bindings); 
  1020.        f2()
  1021.     end
  1022.  
  1023.     and gen cexp =
  1024.     case cexp
  1025.       of RECORD(k,vl,w,e) =>
  1026.           alloc(w, any,  fn w' => let
  1027.         val desc = case (k, length vl)
  1028.              of (RK_VECTOR, l) => make_desc(l, tag_record)
  1029.               | (_, 2) => desc_pair
  1030.               | (_, l) => make_desc(l, tag_record)
  1031.         in
  1032.           record ((immed desc, OFFp 0)
  1033.             :: map (fn(x,p)=>(gpregbind x, p)) vl, w');
  1034.           gen e
  1035.         end)
  1036.           | SELECT(i,INT k,w,e) =>(* the generated code'll never be executed *)
  1037.               alloc(w,any, fn w' => (move(immed(k+k),w'); gen e))
  1038.           | APP(INT k,args) => () (* the generated code'll never be executed *)
  1039.       | SELECT(i,v,w,e) =>
  1040.           alloc(w,any, fn w' => (select(i,gpregbind v,w'); gen e))
  1041.       | OFFSET(i,v,w,e) =>
  1042.           alloc(w, v, fn w' => (offset(i,gpregbind v,w'); gen e))
  1043.       | APP(func as VAR f, args) => 
  1044.            let val formals as dest::_ = standardformals args
  1045.                     in do_shuffle(args,formals);
  1046.                testLimit();
  1047.                jmp(gpregEA dest)
  1048.            end
  1049.       | APP(func as LABEL f, args) =>
  1050.         (case know f
  1051.           of KNOWN(ref(GEN(_,formals))) =>
  1052.                (do_shuffle(args, formals);
  1053.                 jmp(labmap f))
  1054.            | KNOWN_CHECK(ref(GEN(_,formals)),_) =>
  1055.                (do_shuffle(args, formals);
  1056.                 testLimit();
  1057.                 jmp(labmap f))
  1058.            | KNOWN(r as ref(UNGEN(vl,cexp))) =>
  1059.              let val _ =FreeMap.freemap (Intmap.add freemaptable) cexp;
  1060.              val pref = if !CG.floatreg_params then
  1061.                      preferred_register_asgn(vl,cexp)
  1062.                     else map (fn _ => GPReg) vl
  1063.              val formals = if !CG.argrep then
  1064.                             allocparams(args,vl,pref)
  1065.                        else stupidargs(func,args,vl,pref)
  1066.              val lab = labmap f
  1067.              in r := GEN(vl,formals);
  1068.              (*     jmp lab;*)
  1069.              comment(Access.lvarName f ^ ":\n");
  1070.                          define lab;
  1071.                          root1 := root cexp;
  1072.              gen cexp before dispose(cexp,"known_cexp")
  1073.              end
  1074.            | KNOWN_CHECK(r as ref(UNGEN(vl,cexp)), alloc) =>
  1075.              let val _ =FreeMap.freemap (Intmap.add freemaptable) cexp;
  1076.                  val pref = if !CG.floatreg_params then
  1077.                      preferred_register_asgn(vl,cexp)
  1078.                     else map (fn _ => GPReg) vl
  1079.              val formals = if !CG.argrep then
  1080.                             allocparams(args,vl,pref)
  1081.                        else stupidargs(func,args,vl,pref)
  1082.              val lab = labmap f
  1083.              in r := GEN(vl,formals);
  1084.              testLimit();
  1085.              jmp (lab); align(); mark();
  1086.              comment(Access.lvarName f ^ ":\n");
  1087.                          define lab;
  1088.                          checkLimit (alloc*4, lab, regmask formals);
  1089.                          root1 := root cexp;
  1090.              gen cexp
  1091.              end
  1092.            | k as STANDARD _ =>
  1093.               (do_shuffle(args, standardformals args);
  1094.                testLimit();
  1095.                jmp(labmap f))
  1096.                | _ => die "a3 in CPSgen")
  1097.       | APP _ => ErrorMsg.impossible "constant func in CPSgen"
  1098.       | SWITCH(v,_,l) => 
  1099.         let val lab = newlabel()
  1100.             val labs = map (fn _ => newlabel()) l;
  1101.             fun f(i, s::r) = (emitlab(i, s); f(i+4, r))
  1102.               | f(_, nil) = ()
  1103.             fun h(lab::labs, e::es) = 
  1104.             parallel_gen(cexp_freevars e, 
  1105.                      fn () => genlab(lab,e),fn () => h(labs, es))
  1106.               | h(nil,nil) = ()
  1107.               | h _ = die "a4 in CPSgen"
  1108.          in fetchindexl(lab, arithtemp, gpregbind v);
  1109. (*            add(lab,arithtemp,arithtemp);
  1110.             jmp(arithtemp); *)
  1111.             jmpindexb(lab,arithtemp);
  1112. (*            align();   temporarily removed so 68020 will work. *)
  1113.             define lab;
  1114.             f (0, labs);
  1115.             h(labs,l)
  1116.         end
  1117.         | ARITH(P.+, [INT k, w],x,e) =>
  1118.           alloc(x, w, fn x' =>
  1119.             (addt(immed(k+k), gpregbind w, x');
  1120.              gen e))
  1121.         | ARITH(P.+, [w, v as INT _],x,e) => gen(ARITH(P.+,[v,w],x,e))
  1122.         | ARITH(P.+, [v,w],x,e) =>
  1123.           alloc(x, w, fn x' =>
  1124.             (M.sub(immed 1, gpregbind v, arithtemp);
  1125.              addt(arithtemp, gpregbind w, x');
  1126.              gen e))
  1127.         | PURE(P.orb, [v,w],x,e) =>
  1128.           alloc(x, w, fn x' => (orb(gpregbind v, gpregbind w, x'); gen e))
  1129.         | PURE(P.andb, [v,w],x,e) =>
  1130.           alloc(x, w, fn x' =>(andb(gpregbind v, gpregbind w, x'); gen e))
  1131.         | PURE(P.xorb, [INT k, w],x,e) =>
  1132.           alloc(x, w, fn x' =>
  1133.             (xorb(immed(k+k), gpregbind w, x');
  1134.              gen e))
  1135.         | PURE(P.xorb, [w,v as INT _],x,e) => gen(PURE(P.xorb,[v,w],x,e))
  1136.         | PURE(P.xorb, [v,w],x,e) =>
  1137.           alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1138.             (xorb(gpregbind v, gpregbind w, x'');
  1139.              add(immed 1, x'', x');
  1140.              gen e)))
  1141.        | PURE(P.notb, [v],x,e) =>
  1142.           alloc(x, any, fn x' =>
  1143.                 (M.sub(gpregbind v, immed 0, x');
  1144.              gen e))
  1145.        | PURE(P.lshift, [INT k, w],x,e) =>
  1146.          alloc(x,w, fn x' => tempreg(x', fn x'' =>
  1147.            (ashr(immed 1, gpregbind w, x'');
  1148.             ashl(x'',immed(k+k),x'');
  1149.             add(immed 1, x'', x');
  1150.             gen e)))
  1151.        | PURE(P.lshift, [v, INT k],x,e) =>
  1152.          alloc(x,v, fn x' => tempreg(x', fn x'' =>
  1153.            (add(immed ~1, gpregbind v, x'');
  1154.             ashl(immed k, x'', x'');
  1155.             add(immed 1, x'', x');
  1156.             gen e)))
  1157.        | PURE(P.lshift, [v,w],x,e) =>
  1158.          alloc(x,w, fn x' => tempreg(x', fn x'' =>
  1159.            (ashr(immed 1, gpregbind w, arithtemp);
  1160.             add(immed ~1, gpregbind v, x'');
  1161.             ashl(arithtemp, x'', x'');
  1162.             add(immed 1, x'', x');
  1163.             gen e)))
  1164.        | PURE(P.rshift, [v, INT k],x,e) =>
  1165.          alloc(x, v, fn x' => tempreg(x', fn x'' =>
  1166.            (ashr(immed k, gpregbind v, x'');
  1167.             orb(immed 1, x'', x');
  1168.              gen e)))
  1169.        | PURE(P.rshift, [v,w],x,e) =>
  1170.          alloc(x, v, fn x' => tempreg(x', fn x'' =>
  1171.            (ashr(immed 1, gpregbind w, arithtemp);
  1172.             ashr(arithtemp, gpregbind v, x'');
  1173.             orb(immed 1, x'', x');
  1174.             gen e)))
  1175.        | ARITH(P.-, [INT k,w],x,e) =>
  1176.          alloc(x, w, fn x' =>
  1177.            (M.subt(gpregbind w, immed(k+k+2), x');
  1178.             gen e))
  1179.        | ARITH(P.-, [v, INT k],x,e) =>
  1180.          alloc(x, v, fn x' =>
  1181.            (M.subt(immed(k+k), gpregbind v, x');
  1182.             gen e))
  1183.        | ARITH(P.-, [v,w],x,e) =>
  1184.          alloc(x, v, fn x' => tempreg(x', fn x'' =>
  1185.            (M.sub(gpregbind w, gpregbind v, x'');
  1186.             add(immed 1, x'', x');
  1187.             gen e)))
  1188.        | ARITH(P.*, [INT k, INT j],x,e) =>
  1189.         alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1190.          (move(immed k, x'');
  1191.           mult(immed(j+j),x'');
  1192.           add(immed 1, x'', x');
  1193.           gen e)))
  1194.        | ARITH(P.*, [INT 2,w],x,e) => gen(ARITH(P.+,[w,w],x,e))
  1195. (* Perhaps this isn't worth the trouble
  1196.        | ARITH(P.*, [INT 4,w],x,e) => 
  1197.          let val v = mkLvar()
  1198.           in gen(ARITH(P.+,[w,w],v,ARITH(P.+,[VAR v,VAR v],x,e)))
  1199.          end
  1200. *)       | ARITH(P.*, [INT k, w],x,e) =>
  1201.          alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1202.            (ashr(immed 1, gpregbind w, x'');
  1203.             mult(immed(k+k), x'');
  1204.             add(immed 1, x'', x');
  1205.             gen e)))
  1206.        | ARITH(P.*, [v,w as INT _],x,e) => gen(ARITH(P.*,[w,v],x,e))
  1207.        | ARITH(P.*, [v,w],x,e) =>
  1208.            alloc(x,any,fn x' => tempreg(x', fn x'' =>
  1209.              (ashr(immed 1, gpregbind v, arithtemp);
  1210.           M.sub(immed 1, gpregbind w, x'');
  1211.           mult(arithtemp,x'');
  1212.           add(immed 1,x'',x');
  1213.           gen e)))
  1214.        | ARITH(P.div, [INT k, INT j],x,e) =>
  1215.          alloc(x, any, fn x' => tempreg(x', fn x'' =>
  1216.            (move(immed k, x'');
  1217.             divt(immed j, x'');
  1218.             addt(x'',x'',x'');
  1219.             add(immed 1, x'',x');
  1220.             gen e)))
  1221.        | ARITH(P.div, [INT k,w],x,e) =>
  1222.          alloc(x, any, fn x' => tempreg(x', fn x'' =>
  1223.            (ashr(immed 1, gpregbind w, arithtemp);
  1224.             move(immed k, x'');
  1225.             divt(arithtemp,x'');
  1226.             addt(x'',x'',x'');
  1227.             add(immed 1, x'',x');
  1228.             gen e)))
  1229.        | ARITH(P.div, [v, INT k],x,e) =>
  1230.          alloc(x, any, fn x' => tempreg(x', fn x'' =>
  1231.            (ashr(immed 1, gpregbind v, x'');
  1232.             divt(immed k, x'');
  1233.             addt(x'',x'',x'');
  1234.             add(immed 1, x'',x');
  1235.             gen e)))
  1236.        | ARITH(P.div, [v,w],x,e) =>
  1237.             alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1238.           (ashr(immed 1, gpregbind w, arithtemp);
  1239.            ashr(immed 1, gpregbind v, x'');
  1240.            divt(arithtemp,x'');
  1241.            addt(x'',x'',x'');
  1242.            add(immed 1, x'',x');
  1243.            gen e)))
  1244.        | LOOKER(P.!, [v],w,e) => gen (LOOKER(P.subscript, [v, INT 0], w, e))
  1245.        | ARITH(P.~, [v],w,e) =>
  1246.      alloc(w,any,fn w' => (M.subt(gpregbind v,immed 2,w'); gen e))
  1247.        | PURE(P.makeref, [v],w,e) =>
  1248.         alloc(w,any, fn w' =>
  1249.         (record([(immed(make_desc(1,tag_array)),OFFp 0),
  1250.              (gpregbind v, OFFp 0)], w');
  1251.          gen e))
  1252.        | BRANCH(P.lessu, [v,w],_,d,e) =>
  1253.        let val false_lab = newlabel()
  1254.         in rangeChk(gpregbind v, gpregbind w, false_lab);
  1255.         parallel_gen(cexp_freevars d,
  1256.                  fn () => gen d, 
  1257.                  fn () => genlab(false_lab, e))
  1258.        end
  1259.        | BRANCH(P.gequ, [v,w],_,e,d) =>
  1260.        let val false_lab = newlabel()
  1261.         in rangeChk(gpregbind v, gpregbind w, false_lab);
  1262.         parallel_gen(cexp_freevars d,
  1263.                  fn () => gen d, 
  1264.                  fn () => genlab(false_lab, e))
  1265.        end
  1266.        | LOOKER(P.subscript, [v,w],x,e) =>
  1267.             alloc(x,any, fn x' =>
  1268.                 (fetchindexl(gpregbind v, x', gpregbind w);
  1269.                  gen e))
  1270.        | PURE(P.subscriptv,[v,w],x,e) =>
  1271.          alloc(x,any,fn x' => (fetchindexl(gpregbind v,x',gpregbind w);
  1272.                    gen e))
  1273.        | SETTER(P.update, [a, i, v], e) => let
  1274.       val a' = gpregbind a and i' = gpregbind i
  1275.       in
  1276.         recordStore (a', i', false);
  1277.         storeindexl (gpregbind v, a', i');
  1278.         gen e
  1279.       end
  1280.        | SETTER(P.boxedupdate, [a, i, v], e) => let
  1281.       val a' = gpregbind a and i' = gpregbind i
  1282.       in
  1283.         recordStore (a', i', true);
  1284.         storeindexl (gpregbind v, a', i');
  1285.         gen e
  1286.       end
  1287.        | SETTER(P.unboxedupdate, [a, i, v], e) =>
  1288.         (storeindexl(gpregbind v, gpregbind a, gpregbind i);
  1289.          gen e)
  1290.        | PURE(P.length, [a as VAR _], x, e) =>  (* Note: least tag bit is 1 *)
  1291.       alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1292.          (select(~1, gpregbind a, x'');
  1293.           ashr(immed(width_tags-1), x'', x'');
  1294.           move(x'',x');
  1295.           gen e)))
  1296.        | PURE(P.length, [a], x, e) =>  (* Note: least tag bit is 1 *)
  1297.       alloc(x,any, fn x' => tempreg(x', fn x'' =>
  1298.          (move(gpregbind a, x');
  1299.           select(~1,x',x'');
  1300.           ashr(immed(width_tags-1), x'', x'');
  1301.           move(x'',x');
  1302.           gen e)))
  1303.        | PURE(P.objlength, [a], x, e) =>
  1304.       alloc(x,any,  fn x' => tempreg(x', fn x'' =>
  1305.         (select(~1, gpregbind a, x'');
  1306.          ashr(immed(width_tags-1),x'', x'');
  1307.          orb(immed 1, x'', x');
  1308.          gen e)))
  1309.        | SETTER(P.store, [s,INT i', INT v'], e) =>
  1310.          (storeindexb(immed v', gpregbind s, immed i');
  1311.           gen e)
  1312.        | SETTER(P.store, [s,INT i',v], e) =>
  1313.          (ashr(immed 1, gpregbind v, arithtemp);
  1314.           storeindexb(arithtemp, gpregbind s, immed i');
  1315.           gen e)
  1316.        | SETTER(P.store, [s,i,INT v'], e) =>
  1317.          (ashr(immed 1, gpregbind i, arithtemp);
  1318.           storeindexb(immed v', gpregbind s, arithtemp);
  1319.           gen e)
  1320.        | SETTER(P.store, [s,i,v], e) =>
  1321.          let val v' = gpregbind v
  1322.           in ashr(immed 1, gpregbind i, arithtemp);
  1323.          ashr(immed 1, v', v');
  1324.              storeindexb(v', gpregbind s, arithtemp);
  1325.          add(v',v',v');
  1326.          add(immed 1, v', v');
  1327.          gen e
  1328.          end
  1329.        | LOOKER(P.ordof, [s as VAR _, INT k], v, e) =>
  1330.          alloc(v,any, fn v' =>
  1331.            (fetchindexb(gpregbind s, v', immed k);
  1332.             add(v',v',v');
  1333.             add(immed 1, v',v');
  1334.             gen e))
  1335.        | LOOKER(P.ordof, [s, INT k], v, e) =>
  1336.          alloc(v,any, fn v' =>
  1337.            (move(gpregbind s, v');
  1338.             fetchindexb(v', v', immed k);
  1339.             add(v',v',v');
  1340.             add(immed 1, v',v');
  1341.             gen e))
  1342.        | LOOKER(P.ordof, [s as VAR _, i], v, e) =>
  1343.          alloc(v,any, fn v' =>
  1344.            (ashr(immed 1, gpregbind i, arithtemp);
  1345.             fetchindexb(gpregbind s, v', arithtemp);
  1346.             add(v',v',v');
  1347.             add(immed 1, v',v');
  1348.             gen e))
  1349.        | LOOKER(P.ordof, [s, i], v, e) =>
  1350.          alloc(v,any, fn v' =>
  1351.            (ashr(immed 1, gpregbind i, arithtemp);
  1352.             move(gpregbind s, v');
  1353.             fetchindexb(v', v', arithtemp);
  1354.             add(v',v',v');
  1355.             add(immed 1, v',v');
  1356.             gen e))
  1357.        | BRANCH(P.boxed, [x],_,a,b) =>
  1358.             let val lab = newlabel()
  1359.              in bbs(immed 0,gpregbind x,lab); 
  1360.              parallel_gen(cexp_freevars a,
  1361.                       fn () => gen a, 
  1362.                       fn () => genlab(lab,b))
  1363.             end
  1364.        | BRANCH(P.unboxed, x,c,a,b) => gen(BRANCH(P.boxed,x,c,b,a))
  1365.        | LOOKER(P.gethdlr, [],x,e) =>
  1366.           alloc(x,any, fn x' => (move(exnptr,x'); gen e))
  1367.        | SETTER(P.sethdlr, [x],e) => (move(gpregbind x, exnptr); gen e)
  1368.        | LOOKER(P.getvar, [], x, e0 as SETTER(primop, [VAR x',i,v], e)) =>
  1369.             if (varptr_indexable
  1370.         andalso x=x' andalso not (SortedList.member (cexp_freevars e) x))
  1371.               then let
  1372.         val i' = gpregbind i
  1373.         in
  1374.           case primop
  1375.            of P.update => recordStore (varptr, i', false)
  1376.             | P.boxedupdate => recordStore (varptr, i', true)
  1377.             | P.unboxedupdate => ()
  1378.             | _ => ErrorMsg.impossible "[CPSGen: varptr setter]"
  1379.           (* end case *);
  1380.           storeindexl(gpregbind v, varptr, i');
  1381.           gen e
  1382.         end
  1383.           else alloc(x,any, fn x' => (move(varptr,x'); gen e0))
  1384.        | LOOKER(P.getvar,[],x,
  1385.            e0 as LOOKER(P.subscript, [VAR x',y], w, e)) =>
  1386.             if varptr_indexable andalso
  1387.          x=x' andalso not (SortedList.member (cexp_freevars e) x)
  1388.                then alloc(w,any, fn w' =>
  1389.                 (fetchindexl(varptr, w', gpregbind y);
  1390.                  gen e))
  1391.                else alloc(x,any, fn x' => (move(varptr,x'); gen e0))
  1392.        | LOOKER(P.getvar, [],x,e) =>
  1393.               alloc(x,any, fn x' => (move(varptr,x'); gen e))
  1394.        | SETTER(P.setvar, [x],e) => (move(gpregbind x, varptr); gen e)
  1395.        | SETTER(P.uselvar, [x],e) => gen e
  1396.        | LOOKER(P.deflvar, [],x,e) => alloc(x,any, fn x' => gen e)
  1397.        | ARITH(P.fmul, vl, z, e) =>
  1398.          do_fp_primop(vl,z,e,cexp, (fn ([x,y],z) => (fmuld(x,y,z); gen e)))
  1399.        | ARITH(P.fdiv, vl, z, e) =>
  1400.          do_fp_primop(vl,z,e,cexp, (fn ([x,y],z) => (fdivd(x,y,z); gen e)))
  1401.        | ARITH(P.fadd, vl, z, e) =>
  1402.          do_fp_primop(vl,z,e,cexp, (fn ([x,y],z) => (faddd(x,y,z); gen e)))
  1403.        | ARITH(P.fsub, vl, z, e) =>
  1404.          do_fp_primop(vl,z,e,cexp, (fn ([x,y],z) => (fsubd(x,y,z); gen e)))
  1405.        | PURE(P.fnegd, vl, z, e) =>
  1406.          do_fp_primop(vl,z,e,cexp, (fn ([x],y) => (fnegd(x,y); gen e)))
  1407.        | PURE(P.fabsd, vl, z, e) =>
  1408.          do_fp_primop(vl,z,e,cexp, (fn ([x],y) => (fabsd(x,y); gen e)))
  1409.        | PURE(P.real,[v],w,e) => let
  1410.        val gpr = getgpscratch (~1,live_regs(freemap w))
  1411.        val _   = addregbinding (w,GPR gpr)
  1412.        val fpr = force_fpgetscratch (~1,[],e)
  1413.        val wreg = FPR (fpr,gpr)
  1414.      in
  1415.          addregbinding (w,wreg);
  1416.          case v
  1417.            of INT n => cvti2d(immed n, fpregEA wreg)
  1418.         | _ => (ashr(immed 1,gpregbind v,arithtemp);
  1419.             cvti2d(arithtemp,fpregEA wreg))
  1420.          (* end case *);
  1421.          gen e
  1422.      end
  1423.  
  1424. (* still to implement: 
  1425.       floor | round *)
  1426.  
  1427.        | LOOKER(P.subscriptf,[a,i],w,e) =>
  1428.          let val gp = getgpscratch(~1,live_regs(freemap w))
  1429.          val _ = addregbinding(w, GPR gp)
  1430.          val fp = force_fpgetscratch(~1,[],e)
  1431.          val wreg = FPR(fp,gp)
  1432.          in  addregbinding(w, wreg);
  1433.          fetchindexd(gpregbind a, fpregEA wreg, gpregbind i);
  1434.          gen e
  1435.          end    
  1436.        | SETTER(P.updatef,[a,i,v],e) => 
  1437.          let val a' = gpregbind a 
  1438.          val i' = gpregbind i
  1439.          val [fpreg] = move_to_FPRs([v],cexp)
  1440.          in  storeindexd(fpregEA fpreg, gpregbind a, gpregbind i);
  1441.          gen e
  1442.          end
  1443.        | PURE(P.gettag, [v], x, e) =>
  1444.         alloc (x, any, fn x' => tempreg(x', fn x'' => (
  1445.           select(~1, gpregbind v, x'');
  1446.           andb(immed(power_tags-1), x'', x'');
  1447.           ashl(immed 1, x'', x'');
  1448.           orb(immed 1, x'', x');
  1449.           gen e)))
  1450.        | PURE(P.mkspecial, [INT i, v], w, e) =>
  1451.         alloc(w, any, fn w' => (
  1452.           record([
  1453.         (immed(make_desc(i, tag_special)), OFFp 0),
  1454.         (gpregbind v, OFFp 0)], w');
  1455.           gen e))
  1456.        | PURE(P.mkspecial, [i, v], w, e) =>
  1457.         alloc(w, any, fn w' => let
  1458.           val i' = gpregbind i
  1459.           in
  1460.         tempreg (i', fn i'' => (
  1461.           ashr(immed(1), i', i'');
  1462.           ashl(immed(width_tags), i'', i'');
  1463.           orb(immed(desc_special), i'', i');
  1464.           record([(i', OFFp 0), (gpregbind v, OFFp 0)], w');
  1465.           gen e))
  1466.           end)
  1467.        | LOOKER(P.getspecial, [v], x, e) =>
  1468.         alloc (x, any, fn x' => tempreg(x', fn x'' => (
  1469.           select(~1, gpregbind v, x'');
  1470.           ashr(immed(width_tags-1), x'', x'');
  1471.           orb(immed 1, x'', x');
  1472.           gen e)))
  1473.        | SETTER(P.setspecial, [v, INT i], e) => (
  1474.         storeindexl (immed(make_desc(i, tag_special)), gpregbind v, immed ~1);
  1475.         gen e)
  1476.        | SETTER(P.setspecial, [v, i], e) => let
  1477.         val i' = gpregbind i
  1478.         in
  1479.           tempreg (i', fn i'' => (
  1480.         ashr(immed(1), i', i'');
  1481.         ashl(immed(width_tags), i'', i'');
  1482.         orb(immed(desc_special), i'', i');
  1483.         storeindexl (i', gpregbind v, immed ~1);
  1484.         gen e))
  1485.         end
  1486.        | BRANCH(args as (P.ieql,_,_,_,_)) => compare(ibranch,NEQ,args)
  1487.        | BRANCH(args as (P.ineq,_,_,_,_)) => compare(ibranch,EQL,args)
  1488.        | BRANCH(args as (P.>   ,_,_,_,_)) => compare(ibranch,LEQ,args)
  1489.        | BRANCH(args as (P.>=  ,_,_,_,_)) => compare(ibranch,LSS,args)
  1490.        | BRANCH(args as (P.<   ,_,_,_,_)) => compare(ibranch,GEQ,args)
  1491.        | BRANCH(args as (P.<=  ,_,_,_,_)) => compare(ibranch,GTR,args)
  1492.        | BRANCH(args as (P.feql,_,_,_,_)) => fpcompare(fbranchd,NEQ,cexp)
  1493.        | BRANCH(args as (P.fneq,_,_,_,_)) => fpcompare(fbranchd,EQL,cexp)
  1494.        | BRANCH(args as (P.fgt ,_,_,_,_)) => fpcompare(fbranchd,LEQ,cexp)
  1495.        | BRANCH(args as (P.flt ,_,_,_,_)) => fpcompare(fbranchd,GEQ,cexp)
  1496.        | BRANCH(args as (P.fge ,_,_,_,_)) => fpcompare(fbranchd,LSS,cexp)
  1497.        | BRANCH(args as (P.fle ,_,_,_,_)) => fpcompare(fbranchd,GTR,cexp)
  1498.        | _ => ErrorMsg.impossible "3312 in CPSgen"
  1499.  
  1500.     and compare(branch,test, (_,[v,w],_,d,e)) =
  1501.     let val lab = newlabel()
  1502.     in branch(test,gpregbind v, gpregbind w, lab); 
  1503.         parallel_gen(cexp_freevars d,
  1504.              fn () => gen d,
  1505.              fn () => genlab(lab, e))
  1506.     end
  1507.       | compare _ = die "a1 in CPSgen"
  1508.  
  1509.     and
  1510.     fpcompare(branch, test, cexp as BRANCH(_,args as [v,w],_,d,e)) =
  1511.     let val lab = newlabel()
  1512.         val reserved = move_to_FPRs([v,w], cexp)
  1513.         val [v',w'] = reserved 
  1514.     in  branch(test, fpregEA v', fpregEA w', lab);
  1515.         parallel_gen(cexp_freevars d,
  1516.              fn () => gen d,
  1517.              fn () => genlab(lab,e))
  1518.     end
  1519.       | fpcompare _ = die "a2 in CPSgen"
  1520.  
  1521. in  (* not necessary with regmasks: emitlong 1; Bogus tag for spacing, boot_v. *)
  1522.     let fun loop nil = ()
  1523.           | loop (frag::r) = (frags := r; genfrag frag; loop(!frags))
  1524.     in loop(!frags)
  1525.     end
  1526. end (* codegen *)
  1527.  
  1528. end (* structure *)
  1529.